<!--
* @description 高德地图组件
* @fileName index.vue
* @author zero_fsc
* @date 2020/06/30 15:01:32
!-->
<template>
  <div>
    <!-- 地图 -->
    <div :id="id" class="container">
      <!-- 搜索框 -->
      <input v-show="!readOnly" :id="searchId" class="search" :placeholder="placeholder" />
    </div>
  </div>
</template>

<script>
import {
  createRandomId
} from '@/utils'
import {
  warning,
  danger
} from '@/utils/modal'
export default {
  props: {
    lng: {
      type: null,
      default: ''
    },
    lat: {
      type: null,
      default: ''
    },
    addr: {
      type: String,
      default: ''
    },
    readOnly: {
      type: Boolean,
      default: false
    },
    placeholder: {
      type: String,
      default: '请输入地址'
    }
  },
  data () {
    return {
      map: '',
      id: createRandomId(),
      searchId: createRandomId(),
      // 缩放大小
      zoom: 16
    }
  },

  mounted () {
    this.initMap()
  },

  methods: {
    /*
    * @description 初始化地图
    * @fileName index.vue
    * @author zero_fsc
    * @date 2020/06/30 15:13:11
    */
    initMap () {
      this.map = new AMap.Map(this.id, {
        lang: 'zh_cn',
        zoom: this.zoom,
        viewMode: '3D',
        resizeEnable: true
      })
      // 异步加载多个控件
      AMap.service(['AMap.ToolBar', 'AMap.Scale', 'AMap.Geolocation', 'AMap.MouseTool', 'AMap.Autocomplete'], () => {
        // 根据浏览器获取当前定位marker标点控件
        !this.lng && !this.lat ? this.getPositionByBrow() : this.initMarker(this.lng, this.lat)
        // 添加缩放条控件
        this.map.addControl(new AMap.ToolBar())
        // 添加比例尺控件
        this.map.addControl(new AMap.Scale())
        // 添加输入搜索控件
        this.initInput()
      })
    },

    /*
    * @description 创建marker标点 --- 核心控件
    * @fileName index.vue
    * @author zero_fsc
    * @date 2020/06/30 15:20:26
    */
    initMarker (lng, lat) {
      let position = [+lng, +lat] // 统一处理经纬度类型问题 强制类型转换为Number类型
      const marker = new AMap.Marker({
        position: position,
        draggable: !this.readOnly,
        cursor: true,
        raiseOnDrag: false,
        zIndex: 101
      })
      marker.setMap(this.map)
      this.map.setCenter(position) // 设置中心点
      // 逆向地址解析
      this.getPositionByGa(lng, lat)
      // 设置拖拽marker监听事件
      AMap.event.addListener(marker, 'dragend', ({ lnglat }) => this.getMarkerPosition(lnglat.lng, lnglat.lat))
    },

    /*
    * @description 获取拖拽后marker标点详情
    * @fileName index.vue
    * @author zero_fsc
    * @date 2020/06/30 16:54:41
    */
    getMarkerPosition (lng, lat) {
      // 清空上一次marker点
      this.clearMarker()
      this.initMarker(lng, lat)
      // 中心点设置
      this.map.setCenter([+lng, +lat])
    },

    /*
    * @description 逆向地址解析
    * @fileName index.vue
    * @author zero_fsc
    * @date 2020/06/30 16:16:41
    */
    getPositionByGa (lng, lat) { // isClick 用于防止初始化时getCurrentPosition()事件冒泡
      // 通过经纬度反向解析获取当前地址
      const geoCoder = new AMap.Geocoder({
        radius: 1000,
        extensions: 'all'
      })
      geoCoder.getAddress([lng, lat], (status, { info, regeocode }) => {
        if (status === 'complete' && info === 'OK') {
          this.$emit('update:lng', lng)
          this.$emit('update:lat', lat)
          this.$emit('update:addr', regeocode.formattedAddress)
        } else {
          this.onError()
        }
      })
    },

    /*
    * @description 根据浏览器获取当前定位
    * @fileName index.vue
    * @author zero_fsc
    * @date 2020/06/30 15:14:21
    */
    async getPositionByBrow () {
      const _this = this
      const geolocation = new AMap.Geolocation({
        enableHighAccuracy: true, // 是否使用高精度定位，默认:true
        timeout: 10000, // 超过10秒后停止定位，默认：无穷大
        maximumAge: 0, // 定位结果缓存0毫秒，默认：0
        showButton: true, // 显示定位按钮，默认：true
        buttonPosition: 'RB', // 定位按钮停靠位置，默认：'LB'，左下角
        buttonOffset: new AMap.Pixel(10, 20), // 定位按钮与设置的停靠位置的偏移量，默认：Pixel(10, 20)
        showMarker: false, // 定位成功后在定位到的位置显示点标记，默认：true
        panToLocation: true, // 定位成功后将定位到的位置作为地图中心点，默认：true
        zoomToAccuracy: true // 定位成功后调整地图视野范围使定位位置及精度范围视野内可见，默认：false
      })
      geolocation.getCurrentPosition(function (status, { formattedAddress, position }) {
        status === 'complete'
          ? _this.initMarker(position.lng, position.lat)
          : _this.onError()
      })
      // 点击回到当前位置
      this.getCurrentPosition(geolocation)
      this.map.addControl(geolocation)
    },

    /*
    * @description 点击回到当前位置
    * @fileName index2.vue
    * @author zero_fsc
    * @date 2020/06/30 18:21:45
    */
    getCurrentPosition (geolocation) {
      AMap.event.addListener(geolocation, 'complete', ({ type, info, position }) => {
        type === 'complete' && info === 'SUCCESS'
          ? this.initMarker(position.lng, position.lat)
          : this.onError()
      })
    },

    /*
    * @description 初始化搜索
    * @fileName index.vue
    * @author zero_fsc
    * @date 2020/06/30 16:58:43
    */
    initInput () {
      const mapAuto = new AMap.Autocomplete({
        input: this.searchId
      })
      AMap.event.addListener(mapAuto, 'select', ({ poi }) => {
        if (!poi) {
          danger(this, '获取位置信息失败，请重新选择')
          return false
        }
        this.clearMarker()
        // 标点重加载
        this.initMarker(poi.location.lng, poi.location.lat)
      })
    },

    /*
    * @description 定位错误统一处理
    * @fileName index.vue
    * @author zero_fsc
    * @date 2020/06/30 16:14:15
    */
    onError () { warning(this, '定位失败, 请刷新重试') },

    /*
    * @description 清除所有marker点 --- 用于输入定位重新打点
    * @fileName index2.vue
    * @author zero_fsc
    * @date 2020/06/30 18:04:46
    */
    clearMarker () { this.map.clearMap() }
  }
}

</script>
<style lang="scss" scoped>
.container {
  position: relative;
  width: 30em !important;
  height: 50em;
}
#marker-btn {
  position: absolute;
  z-index: 1;
  left: 8%;
}
.el-input {
  width: 30em;
  margin-bottom: 10px;
}
/* 解决element dialog z-index 过高导致的覆盖效果 */
.amap-sug-result {
  z-index: 5000 !important;
}
.search{
  position: absolute;
  z-index: 100;
  top: 20px;
  left: 80px;
  width: 250px;
  height: 32px;
  border-radius: 50px;
  border: none;
  padding: 0 24px;
  &:focus {
    border: 0;
    outline: none;
    border-style: none;
    border-radius: 50px;
    border: 1px solid #409EFF;
  }
}
</style>
